﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;

namespace Tilver.Common
{
    public class IdCardStruct
    {
        private static Dictionary<byte, string> _cardCode = new Dictionary<byte, string>();
        private static byte[] b = new byte[] { 7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2 };
        private static char[] c = new char[] { '1', '0', 'X', '9', '8', '7', '6', '5', '4', '3', '2' };

        static IdCardStruct()
        {
            _cardCode.Add(11, "北京");
            _cardCode.Add(12, "天津");
            _cardCode.Add(13, "河北");
            _cardCode.Add(14, "山西");
            _cardCode.Add(15, "内蒙古");
            _cardCode.Add(0x15, "辽宁");
            _cardCode.Add(0x16, "吉林");
            _cardCode.Add(0x17, "黑龙江");
            _cardCode.Add(0x1f, "上海");
            _cardCode.Add(0x20, "江苏");
            _cardCode.Add(0x21, "浙江");
            _cardCode.Add(0x22, "安徽");
            _cardCode.Add(0x23, "福建");
            _cardCode.Add(0x24, "江西");
            _cardCode.Add(0x25, "山东");
            _cardCode.Add(0x29, "河南");
            _cardCode.Add(0x2a, "湖北");
            _cardCode.Add(0x2b, "湖南");
            _cardCode.Add(0x2c, "广东");
            _cardCode.Add(0x2d, "广西");
            _cardCode.Add(0x2e, "海南");
            _cardCode.Add(50, "重庆");
            _cardCode.Add(0x33, "四川");
            _cardCode.Add(0x34, "贵州");
            _cardCode.Add(0x35, "云南");
            _cardCode.Add(0x36, "西藏");
            _cardCode.Add(0x3d, "陕西");
            _cardCode.Add(0x3e, "甘肃");
            _cardCode.Add(0x3f, "青海");
            _cardCode.Add(0x40, "宁夏");
            _cardCode.Add(0x41, "新疆");
            _cardCode.Add(0x47, "台湾");
            _cardCode.Add(0x51, "香港");
            _cardCode.Add(0x52, "澳门");
            _cardCode.Add(0x5b, "国外");
        }
        /// <summary>
        /// 判断身份证是否有效
        /// </summary>
        /// <param name="cardno"></param>
        /// <returns></returns>
        public static bool IsValid(string cardno)
        {
            bool flag = Regex.IsMatch(cardno, @"(^\d{15}$)|(^\d{17}([0-9]|X)$)");
            if (flag)
            {
                flag = _cardCode.ContainsKey(byte.Parse(cardno.Substring(0, 2)));
            }
            if (!flag || (cardno.Length != 0x12))
            {
                return flag;
            }
            int num = 0;
            for (int i = 0; i < 0x11; i++)
            {
                char ch = cardno[i];
                num += int.Parse(ch.ToString()) * b[i];
            }
            return (c[num % 11] == cardno[0x11]);
        }
        /// <summary>
        /// 格式化身份证信息
        /// </summary>
        /// <param name="cardno"></param>
        /// <returns></returns>
        public static IdCardStruct Parser(string cardno)
        {
            if (!IsValid(cardno))
            {
                throw new ArgumentException("身份证号码错误。");
            }
            Regex regex = null;
            string[] strArray = null;
            if (cardno.Length == 0x12)
            {
                regex = new Regex(@"^(\d{2})(\d{4})(\d{8})(\d{3})([0-9]|X)$");
                strArray = regex.Split(cardno);
            }
            else if (cardno.Length == 15)
            {
                strArray = new Regex(@"^(\d{2})(\d{4})(\d{6})(\d{3})$").Split(cardno);
                strArray[3] = "19" + strArray[3];
            }

            return new IdCardStruct()
            {
                IdCardNo = cardno,
                Province = _cardCode[byte.Parse(strArray[1])],
                Birthday = DateTime.ParseExact(strArray[3], "yyyyMMdd", null),
                Sex = (int.Parse(strArray[4]) % 2) != 0
            };
        }
        /// <summary>
        /// 生日
        /// </summary>
        public DateTime Birthday
        {
            get;
            internal set;
        }
        /// <summary>
        /// 身份证号码
        /// </summary>
        public string IdCardNo
        {
            get;
            internal set;
        }
        /// <summary>
        /// 所在省
        /// </summary>
        public string Province
        {
            get;
            internal set;
        }
        /// <summary>
        /// 性别
        /// </summary>
        public bool Sex
        {
            get;
            internal set;
        }
    }
}
